{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to Knowledge Graphs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
    "<div class=\"toc\">\n",
    "    <ul class=\"toc-item\">\n",
    "        <li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span>\n",
    "            <ul>\n",
    "                <li><span><a href=\"#What-is-a-knowledge-graph?\" data-toc-modified-id=\"What-is-a-knowledge-graph?-1.1\">What is a knowledge graph?</a></span></li>\n",
    "                <li><span><a href=\"#Key-Terms\" data-toc-modified-id=\"Key-Terms-1.2\">Key Terms</a></span></li>\n",
    "            </ul>\n",
    "        </li>\n",
    "        <li><span><a href=\"#Connect\" data-toc-modified-id=\"Connect-2\">Connect</a></span></li>\n",
    "        <li><span><a href=\"#Create\" data-toc-modified-id=\"Create-3\">Create</a></span></li>\n",
    "        <li><span><a href=\"#Data-Model\" data-toc-modified-id=\"Data-Model-4\">Data Model</a></span></li>\n",
    "        <li><span><a href=\"#Path-Forward\" data-toc-modified-id=\"Path-Forward-5\">Path Forward</a></span></li>\n",
    "    </ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "ArcGIS Knowledge integrates graph and spatial analytics to support data discovery, collaborative investigations, link analysis, and information sharing across organizations. An ArcGIS Enterprise portal configured for ArcGIS Knowledge is required. Find out more at [Configure ArcGIS Knowledge](https://enterprise.arcgis.com/en/knowledge/latest/introduction/configure-arcgis-knowledge.htm)\n",
    "\n",
    "In order to use the [`arcgis.graph`](https://developers.arcgis.com/python/api-reference/arcgis.graph.html) capabilities in the ArcGIS API for Python, you must have an existing knowledge graph. Learn more about [creating knowledge graphs](https://pro.arcgis.com/en/pro-app/latest/help/data/knowledge/create-an-investigation-in-a-project.htm)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### What is a knowledge graph?\n",
    "A knowledge graph consists of entities and the relationships between them. Each of these entities and relationships can also have properties that contain information describing the entity or relationship. Entities in the model represent real-world objects, concepts, or events. Relationships in the model express how entities are associated with each other. \n",
    "\n",
    "### Key Terms\n",
    "A few key terms to understand are:\n",
    "- Knowledge Graph: A network that connects people, places, things, and events with each other through relationships.\n",
    "- Data Model: Defines the types of entities and relationships that can exist in the knowledge graph along with their properties.\n",
    "- Entity: Representation of a specific thing in the graph such as a person, building, vehicle, etc. These can have any number of properties and be either spatial or nonspatial.\n",
    "- Relationship: Connects two entities in the graph and represents their relationship such as knows, works_at, drives, etc. These can have any number of properties and are nonspatial.\n",
    "- Properties: key-value pairs that describe the entity or relationships such as name, start_date, make, model, etc."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connect\n",
    "\n",
    "Using the ArcGIS API for Python, you can connect to a [`KnowledgeGraph`](https://developers.arcgis.com/python/latest/api-reference/arcgis.graph.html#knowledgegraph) with [`arcgis.graph`](https://developers.arcgis.com/python/latest/api-reference/arcgis.graph.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from arcgis.gis import GIS\n",
    "from arcgis.graph import KnowledgeGraph\n",
    "\n",
    "url = \"https://myHostName.domain.com/server/rest/services/Hosted/myServiceName/KnowledgeGraphServer\"\n",
    "gis = GIS(\"home\")\n",
    "knowledge_graph = KnowledgeGraph(url=url, gis=gis)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A knowledge graph service is composed of two primary resources, the data and data model. The data contains entities and relationships with their associated properties. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create\n",
    "Using the ArcGIS API for Python, you can create a new Knowledge Graph using [`create_service()`](https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#arcgis.gis.ContentManager.create_service)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gis = GIS(\"home\")\n",
    "result = gis.content.create_service(\n",
    "    name=\"myKnowledgeGraph\",\n",
    "    capabilities=\"Query,Editing,Create,Update,Delete\",\n",
    "    service_type=\"KnowledgeGraph\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Services can also be created using create parameters to choose more service options."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = gis.content.create_service(\n",
    "    name=\"\",\n",
    "    service_type=\"KnowledgeGraph\",\n",
    "    create_params={\n",
    "        \"name\": \"myKnowledgeGraph\",\n",
    "        \"capabilities\": \"Query\",\n",
    "        \"jsonProperties\": {\n",
    "            \"supportsProvenance\": False,\n",
    "            \"arcgisManagedData\": False,\n",
    "            \"dataSourceItemID\": \"f63a6725058c4c05a63480521acffe01\",\n",
    "        },\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, the result from create_service can be used to initialize the KnowledgeGraph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge_graph = KnowledgeGraph(url=result.url, gis=gis)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Model\n",
    "\n",
    "The data model defines the schema of the knowledge graph by defining the entity types and relationship types in the graph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "knowledge_graph.query_data_model(as_dict=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The response from `query_data_model()` has many useful components that describe the schema of the knowledge graph. When `as_dict` is set to `False`, the response will be a `GraphDataModel`. Important information to look for on the data model includes spatial reference, strictness, whether the service is arcgis managed, information on the unique identifier property, and search indexes. The data model also includes detailed information on each entity and relationship type.\n",
    "\n",
    "```\n",
    "GraphDataModel(\n",
    "    data_model_timestamp=1737573982389, \n",
    "    spatial_reference={'wkid': 4326}, \n",
    "    entity_types=[\n",
    "        EntityType(\n",
    "            name='Vehicle', \n",
    "            alias='', \n",
    "            role='esriGraphNamedObjectRegular', \n",
    "            strict=False, \n",
    "            properties=[\n",
    "                GraphProperty(name='objectid', alias='objectid', domain='', field_type='esriFieldTypeOID', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=False, visible=True, editable=False, required=True, is_system_maintained=True, role='esriGraphPropertyRegular'), \n",
    "                GraphProperty(name='globalid', alias='globalid', domain='', field_type='esriFieldTypeGlobalID', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=False, visible=True, editable=False, required=True, is_system_maintained=True, role='esriGraphPropertyRegular'), \n",
    "                GraphProperty(name='make', alias='', domain='', field_type='esriFieldTypeString', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=True, visible=True, editable=True, required=False, is_system_maintained=False, role='esriGraphPropertyRegular')\n",
    "            ], \n",
    "            field_indexes=[\n",
    "                FieldIndex(name='esri__oid_idx', is_ascending=True, is_unique=True, fields=['objectid']), \n",
    "                FieldIndex(name='esri__globalid_idx', is_ascending=True, is_unique=True, fields=['globalid'])\n",
    "            ]\n",
    "        )\n",
    "    ],\n",
    "    search_indexes=[\n",
    "        SearchIndex(\n",
    "            name='esri__search_idx', \n",
    "            supported_category='both_entity_relationship', \n",
    "            analyzers=[SearchAnalyzer(name='text_en'), \n",
    "            SearchAnalyzer(name='identity')], \n",
    "            search_properties={\n",
    "                'Document': SearchIndexProperties(property_names=['metadata', 'keywords', 'fileExtension', 'globalid', 'name', 'text', 'title', 'contentType', 'url']), \n",
    "                'HasDocument': SearchIndexProperties(property_names=['globalid']), \n",
    "                'Vehicle': SearchIndexProperties(property_names=['globalid', 'make'])\n",
    "            }\n",
    "        )\n",
    "    ], \n",
    "    provenance_source_type_values=ProvenanceSourceTypeValues(value_behavior_array=[]), \n",
    "    constraint_rules=[\n",
    "        RelationshipExclusionRule(name='HasDocumentRule', alias=\"Relationships of type 'HasDocument' can only have a destination entity of type 'Document'.\", disabled=False, role='esriGraphConstraintRuleRoleHasDocument', type='esriGraphRelationshipExclusionRuleType', origin_entity_types=SetOfNamedTypes(set=[], set_complement=[]), relationship_types=SetOfNamedTypes(set=['HasDocument'], set_complement=[]), destination_entity_types=SetOfNamedTypes(set=[], set_complement=['Document']))\n",
    "    ]\n",
    ")\n",
    "```\n",
    "\n",
    "Entity and relationship types each have a format very similar to each other including basic information about the type like the name, role and strictness as well as properties and field indexes on the type. For a single type, this could look like:\n",
    "```\n",
    "EntityType(\n",
    "    name='Vehicle', \n",
    "    alias='', \n",
    "    role='esriGraphNamedObjectRegular', \n",
    "    strict=False, \n",
    "    properties=[\n",
    "        GraphProperty(name='objectid', alias='objectid', domain='', field_type='esriFieldTypeOID', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=False, visible=True, editable=False, required=True, is_system_maintained=True, role='esriGraphPropertyRegular'), \n",
    "        GraphProperty(name='globalid', alias='globalid', domain='', field_type='esriFieldTypeGlobalID', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=False, visible=True, editable=False, required=True, is_system_maintained=True, role='esriGraphPropertyRegular'), \n",
    "        GraphProperty(name='make', alias='', domain='', field_type='esriFieldTypeString', geometry_type=None, has_z=False, has_m=False, default_value=None, nullable=True, visible=True, editable=True, required=False, is_system_maintained=False, role='esriGraphPropertyRegular')\n",
    "    ], \n",
    "    field_indexes=[\n",
    "        FieldIndex(name='esri__oid_idx', is_ascending=True, is_unique=True, fields=['objectid']), \n",
    "        FieldIndex(name='esri__globalid_idx', is_ascending=True, is_unique=True, fields=['globalid'])\n",
    "    ]\n",
    ")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Path Forward\n",
    "\n",
    "The knowledge graph can be used to <a href=\"part2-search-query-knowledge-graph.ipynb\">search and query a knowledge graph</a> as well as <a href=\"part3-edit-knowledge-graph.ipynb\">add, update and delete</a> types and instances of the data. These will help you to create and use your knowledge graphs."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "d622b5871f1605057390dea3c8b45e995d0d19bef8604acd7f5b2e1066a85139"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
